#include "bsp_uart_stm32f103.h"
#include "bsp_common_stm32f103.h"
#include "stm32f1xx.h"
#include "string.h"

void Bsp_UartInit_(void)
{

}

void Bsp_UartDone_(void)
{
    Bsp_UartClose_();
}

void Bsp_UartOpen_(void)
{

}

void Bsp_UartClose_(void)
{
    Bsp_TUartUnion* self =  &g_bsp_uart_union;

    for (Int8 i = 0; i < self->count; i++)
        self->items[i].is_open = False;
}

static void Bsp_UartInitItemMember_(Bsp_TUartItem* item)
{
    item->rx_pos = 0;
    item->tx_pos = 0;
    item->tx_last_pos = 0;
    item->rx_last_pos = 0;
    item->is_busy = False;

    item->is_open = False;
}

Bsp_THandle Bsp_UartCreate(Int32 id, Int8* tx_buf, UInt32 tx_buf_size, Int8* rx_buf, UInt32 rx_buf_size)
{
    Bsp_THandle result;
    Bsp_TUartUnion* self = &g_bsp_uart_union;
    Int8 index;
    BSP_GET_INDEX(index, id);

    if (index >= 0 && tx_buf != NULL && tx_buf_size > 0 && rx_buf != NULL && rx_buf_size > 0)
    {
        Bsp_TUartItem* item = &self->items[index];

        item->user_data = NULL;
        item->on_send = NULL;
        item->on_recv = NULL;
        item->tx_buf = tx_buf;
        item->tx_buf_size = tx_buf_size;
        item->rx_buf = rx_buf;
        item->rx_buf_size = rx_buf_size;
        Bsp_UartInitItemMember_(item);

        result = item;
    }
    else
        result = NULL;

    return result;
}

void Bsp_UartFree(Bsp_THandle handle)
{
    Bsp_TUartUnion* self = &g_bsp_uart_union;
    Bool is_ok;

    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TUartItem* item = (Bsp_TUartItem*)handle;

        Bsp_UartClose(handle);
        
        item->user_data = NULL;
        item->on_send = NULL;
        item->on_recv = NULL;
        item->tx_buf = NULL;
        item->tx_buf_size = 0;
        item->rx_buf = NULL;
        item->rx_buf_size = 0;
    }
}

Int32 Bsp_UartGetId(Bsp_THandle handle)
{
    Int32 result;
    Bsp_TUartUnion* self = &g_bsp_uart_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TUartItem* item = (Bsp_TUartItem*)handle;

        result = item->id;
    }
    else
        result = Bsp_kErrorCodeParam;

    return result;
}

void* Bsp_UartGetUserData(Bsp_THandle handle)
{
    void* result;
    Bsp_TUartUnion* self = &g_bsp_uart_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TUartItem* item = (Bsp_TUartItem*)handle;

        result = item->user_data;
    }
    else
        result = NULL;

    return result;
}

void Bsp_UartSetUserData(Bsp_THandle handle, void *user_data)
{
    Bsp_TUartUnion* self = &g_bsp_uart_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TUartItem* item = (Bsp_TUartItem*)handle;

        item->user_data = user_data;
    }
}

Int32 Bsp_UartSetEvent(Bsp_THandle handle, Bsp_TUartEvent which_event, void* on_event)
{
    Int32 result;
    Bsp_TUartUnion* self = &g_bsp_uart_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);
    is_ok = is_ok && which_event < Bsp_kUartEventMax;

    if (is_ok)
    {
        Bsp_TUartItem* item = (Bsp_TUartItem*)handle;

        switch (which_event)
        {
        case Bsp_kUartEventOnSend: 
            item->on_send = (Bsp_TUartOnSendEvent)on_event;
            break;

        case Bsp_kUartEventOnRecv: 
            item->on_recv = (Bsp_TUartOnRecvEvent)on_event;
            break;

        default:
            break;
        }

        result = Bsp_kErrorCodeSuccess;
    }
    else
        result = Bsp_kErrorCodeParam;

    return result;
}

Int32 Bsp_UartOpen(Bsp_THandle handle, Int32 baudrate, Int32 parity)
{
    Int32 result;
    Bsp_TUartUnion* self = &g_bsp_uart_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);
    is_ok = is_ok && baudrate > 0 && parity < Bsp_kUartParityMax;

    if (is_ok)
    {
        Bsp_TUartItem* item = (Bsp_TUartItem*)handle;
        
        if (!item->is_open)
        {
            Bsp_UartInitItemMember_(item);
            item->baudrate = baudrate;
            item->parity = parity;

            Drv_UartOpen(item);

            item->is_open = True;

            result = Bsp_kErrorCodeSuccess;
        }
        else
            result = Bsp_kErrorCodeOpened;
    }
    else
        result = Bsp_kErrorCodeParam;

    return result;    
}

Int32 Bsp_UartClose(Bsp_THandle handle)
{
    Int32 result;
    Bsp_TUartUnion* self = &g_bsp_uart_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TUartItem* item = (Bsp_TUartItem*)handle;
        
        if (item->is_open)
        {
            Drv_UartClose(item);

            item->is_open = False;

            result = Bsp_kErrorCodeSuccess;
        }
        else
            result = Bsp_kErrorCodeClosed;
    }
    else
        result = Bsp_kErrorCodeParam;

    return result;    
}

Int32 Bsp_UartGetBaudrate(Bsp_THandle handle)
{
    Int32 result;
    Bsp_TUartUnion* self = &g_bsp_uart_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TUartItem* item = (Bsp_TUartItem*)handle;

        if (item->is_open)
            result = item->baudrate;
        else
            result = Bsp_kErrorCodeClosed;
    }
    else
        result = Bsp_kErrorCodeParam;

    return result;
}

Bool Bsp_UartIsOpen(Bsp_THandle handle)
{
    Bool result;
    Bsp_TUartUnion* self = &g_bsp_uart_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TUartItem* item = (Bsp_TUartItem*)handle;

        result = item->is_open;
    }
    else
        result = False;

    return result;
}

Int32 Bsp_UartRead(Bsp_THandle handle, void *buf, UInt32 size)
{
    Int32 result;
    Bsp_TUartUnion* self = &g_bsp_uart_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TUartItem* item = (Bsp_TUartItem*)handle;

        if (item->is_open)
        {
            result = Drv_UartRead(item, buf, size);
        }
        else
            result = Bsp_kErrorCodeClosed;
    }
    else
        result = Bsp_kErrorCodeParam;

    return result;
}

Int32 Bsp_UartWrite(Bsp_THandle handle, const void *data, UInt32 size)
{
    Int32 result;
    Bsp_TUartUnion* self = &g_bsp_uart_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TUartItem* item = (Bsp_TUartItem*)handle;

        if (item->is_open)
        {
            result = Drv_UartWrite(item, data, size);
        }
        else
            result = Bsp_kErrorCodeClosed;
    }
    else
        result = Bsp_kErrorCodeParam;

    return result;
}

Int32 Bsp_UartReadableCount(Bsp_THandle handle)
{
    Int32 result;
    Bsp_TUartUnion* self = &g_bsp_uart_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TUartItem* item = (Bsp_TUartItem*)handle;

        if (item->is_open)
            result = Drv_UartReadableCount(item);
        else
            result = Bsp_kErrorCodeClosed;
    }
    else
        result = Bsp_kErrorCodeParam;

    return result;
}

Int32 Bsp_UartWritableCount(Bsp_THandle handle)
{
    Int32 result;
    Bsp_TUartUnion* self = &g_bsp_uart_union;
    Bool is_ok;
    BSP_ASSERT_HANDLE(is_ok, handle);

    if (is_ok)
    {
        Bsp_TUartItem* item = (Bsp_TUartItem*)handle;

        if (item->is_open)
            result = item->tx_buf_size - item->tx_pos;
        else
            result = Bsp_kErrorCodeClosed;
    }
    else
        result = Bsp_kErrorCodeParam;

    return result;
}
